package cn.tedu.submarine;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Random;
import java.util.Arrays;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
/** 整个游戏窗口 */
public class World extends JPanel {
    public static final int WIDTH = 641; //窗口宽
    public static final int HEIGHT = 479; //窗口高

    public static final int START = 0;     //启动状态
    public static final int RUNNING = 1;   //运行状态
    public static final int GAME_OVER = 2; //游戏结束状态
    private int state = START; //当前状态(默认为启动状态)

    private Battleship ship = new Battleship(); //战舰
    private SeaObject[] submarines = {};        //潜艇(侦察潜艇、鱼雷潜艇、水雷潜艇)数组
    private SeaObject[] thunders = {};          //雷(鱼雷、水雷)数组
    private Bomb[] boms = {};                   //深水炸弹数组

    /** 生成潜艇(侦察潜艇、鱼雷潜艇、水雷潜艇)对象 */
    public SeaObject nextSubmarine(){
        Random rand = new Random(); //随机数对象
        int type = rand.nextInt(20); //0到19
        if(type<10){ //0到9时，返回侦察潜艇对象
            return new ObserveSubmarine();
        }else if(type<16){ //10到15时，返回鱼雷潜艇对象
            return new TorpedoSubmarine();
        }else{ //16到19时，返回水雷潜艇对象
            return new MineSubmarine();
        }
    }

    private int subEnterIndex = 0; //潜艇入场计数
    /** 潜艇(侦察潜艇、鱼雷潜艇、水雷潜艇)入场 */
    public void submarineEnterAction(){ //每10毫秒走一次
        subEnterIndex++; //每10毫秒增1
        if(subEnterIndex%40==0){ //每400(10*40)毫秒走一次
            SeaObject obj = nextSubmarine(); //获取潜艇对象
            submarines = Arrays.copyOf(submarines,submarines.length+1); //扩容
            submarines[submarines.length-1] = obj; //将obj添加到submarines的末尾
        }
    }

    private int thunderEnterIndex = 0; //雷入场计数
    /** 雷(鱼雷、水雷)入场 */
    public void thunderEnterAction(){ //每10毫秒走一次
        thunderEnterIndex++; //每10毫秒增1
        if(thunderEnterIndex%100==0){ //每1000(100*10)毫秒走一次
            for(int i=0;i<submarines.length;i++){ //遍历所有潜艇
                SeaObject obj = submarines[i].shootThunder(); //获取潜艇发出来的雷
                if(obj!=null){ //有雷
                    thunders = Arrays.copyOf(thunders,thunders.length+1); //扩容
                    thunders[thunders.length-1] = obj; //将发射出的雷obj添加到thunders的末尾
                }
            }
        }
    }

    /** 海洋对象移动 */
    public void moveAction(){ //每10毫秒走一次
        for(int i=0;i<submarines.length;i++){ //遍历所有潜艇
            submarines[i].move(); //潜艇移动
        }
        for(int i=0;i<thunders.length;i++){ //遍历所有雷
            thunders[i].move(); //雷移动
        }
        for(int i=0;i<boms.length;i++){ //遍历所有深水炸弹
            boms[i].move(); //深水炸弹移动
        }
    }

    /** 删除越界的海洋对象----避免内存泄漏 */
    public void outOfBoundsAction(){ //每10毫秒走一次
        for(int i=0;i<submarines.length;i++){ //遍历所有潜艇
            if(submarines[i].isOutOfBounds() || submarines[i].isDead()){ //越界了，或者，是死了的
                submarines[i] = submarines[submarines.length-1]; //将越界潜艇替换为最后一个元素
                submarines = Arrays.copyOf(submarines,submarines.length-1); //缩容
            }
        }

        for(int i=0;i<thunders.length;i++){ //遍历所有雷
            if(thunders[i].isOutOfBounds() || thunders[i].isDead()){ //越界了，或者，是死了的
                thunders[i] = thunders[thunders.length-1]; //将越界雷替换为最后一个元素
                thunders = Arrays.copyOf(thunders,thunders.length-1); //缩容
            }
        }

        for(int i=0;i<boms.length;i++){ //遍历所有深水炸弹
            if(boms[i].isOutOfBounds() || boms[i].isDead()){ //越界了，或者，是死了的
                boms[i] = boms[boms.length-1]; //将越界深水炸弹替换为最后一个元素
                boms = Arrays.copyOf(boms,boms.length-1); //缩容
            }
        }
    }

    private int score = 0; //玩家的得分
    /** 深水炸弹与潜艇的碰撞 */
    public void bombBangAction(){ //每10毫秒走一次
        for(int i=0;i<boms.length;i++){ //遍历所有深水炸弹
            Bomb b = boms[i]; //获取每一个深水炸弹
            for(int j=0;j<submarines.length;j++){ //遍历所有潜艇
                SeaObject s = submarines[j]; //获取每一个潜艇
                if(b.isLive() && s.isLive() && s.isHit(b)){ //若都活着并且还撞上了
                    s.goDead(); //潜艇去死
                    b.goDead(); //深水炸弹去死
                    if(s instanceof EnemyScore){ //若被撞潜艇能得分
                        EnemyScore es = (EnemyScore)s; //则将被撞潜艇强转为得分接口
                        score += es.getScore(); //玩家得分
                    }
                    if(s instanceof EnemyLife){ //若被撞潜艇能得命
                        EnemyLife el = (EnemyLife)s; //则将被撞潜艇强转为得命接口
                        int num = el.getLife(); //获取命数
                        ship.addLife(num); //战舰增命
                    }
                }
            }
        }
    }

    /** 雷与战舰的碰撞 */
    public void thunderBangAction(){ //每10毫秒走一次
        for(int i=0;i<thunders.length;i++){ //遍历所有雷
            SeaObject t = thunders[i]; //获取每一个雷
            if(t.isLive() && ship.isLive() && t.isHit(ship)){ //若都活着并且还撞上了
                t.goDead(); //雷去死
                ship.subtractLife(); //战舰减命
            }
        }
    }

    /** 检测游戏结束 */
    public void checkGameOverAction(){ //每10毫秒走一次
        if(ship.getLife()<=0){ //若战舰的命数<=0，表示游戏结束了
            state = GAME_OVER; //则将当前状态修改为GAME_OVER游戏结束状态
        }
    }

    /** 启动程序的执行 */
    public void action(){
        KeyAdapter k = new KeyAdapter() {
            /** 重写keyReleased键盘按键抬起事件 */
            public void keyReleased(KeyEvent e) { //键盘抬起时自动触发
                if(e.getKeyCode()==KeyEvent.VK_SPACE){ //若按下的是空格键
                    switch(state){ //根据当前状态做不同的处理
                        case START: //启动状态时，修改为运行状态
                            state = RUNNING;
                            break;
                        case RUNNING: //运行状态时，发射深水炸弹
                            Bomb obj = ship.shoot(); //获取战舰发射的深水炸弹
                            boms = Arrays.copyOf(boms,boms.length+1); //扩容
                            boms[boms.length-1] = obj; //将深水炸弹添加到最后一个元素上
                            break;
                        case GAME_OVER: //游戏结束状态时
                            score = 0; //清理现场
                            ship = new Battleship();
                            submarines = new SeaObject[0];
                            thunders = new SeaObject[0];
                            boms = new Bomb[0];
                            state = START; //修改为启动状态
                            break;
                    }
                }
                if(e.getKeyCode()==KeyEvent.VK_LEFT){ //若按下的是左移键
                    ship.moveLeft(); //战舰左移
                }
                if(e.getKeyCode()==KeyEvent.VK_RIGHT){ //若按下的是右移键
                    ship.moveRight(); //战舰右移
                }
            }
        }; //侦听器对象
        this.addKeyListener(k); //添加侦听

        Timer timer = new Timer(); //定时器对象
        int interval = 10; //定时间隔(以毫秒为单位)
        timer.schedule(new TimerTask() {
            public void run() { //定时干的事(每10毫秒自动执行)
                if(state==RUNNING){ //仅在运行状态下执行
                    submarineEnterAction(); //潜艇(侦察潜艇、鱼雷潜艇、水雷潜艇)入场
                    thunderEnterAction();   //雷(鱼雷、水雷)入场
                    moveAction();           //海洋对象移动
                    outOfBoundsAction();    //删除越界的海洋对象
                    bombBangAction();       //深水炸弹与潜艇的碰撞
                    thunderBangAction();    //雷与战舰的碰撞
                    checkGameOverAction();  //检测游戏结束
                }
                repaint(); //重新调用paint()方法----不用理解
            }
        }, interval, interval); //定时计划表
    }

    /** 重写paint()画  g:画笔 */
    public void paint(Graphics g){ //每10毫秒走一次
        switch(state){ //根据当前状态做不同的处理
            case START: //启动状态时画启动图
                Images.start.paintIcon(null,g,0,0);
                break;
            case GAME_OVER: //游戏结束状态时画游戏结束图
                Images.gameover.paintIcon(null,g,0,0);
                break;
            case RUNNING: //运行状态时，......
                Images.sea.paintIcon(null,g,0,0); //画海洋图
                ship.paintImage(g); //画战舰
                for(int i=0;i<submarines.length;i++){ //遍历所有潜艇
                    submarines[i].paintImage(g); //画潜艇
                }
                for(int i=0;i<thunders.length;i++){ //遍历所有雷
                    thunders[i].paintImage(g); //画雷
                }
                for(int i=0;i<boms.length;i++){ //遍历所有深水炸弹
                    boms[i].paintImage(g); //画深水炸弹
                }
                g.drawString("SCORE :"+score,200,50);
                g.drawString("LIFE: "+ship.getLife(),400,50);
        }
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        World world = new World();
        world.setFocusable(true);
        frame.add(world);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(World.WIDTH+16, World.HEIGHT+39);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true); //尽快自动调用paint()方法

        world.action(); //启动程序的执行
    }

}
























